package com.hlk.zuul.filters;

import com.hlk.enums.ResponseStatusEnum;
import com.hlk.result.Result;
import com.hlk.utils.IPUtil;
import com.hlk.utils.JsonUtils;
import com.hlk.utils.redis.RedisKeys;
import com.hlk.utils.redis.RedisUtils;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @author hlk
 * @version 1.0
 * @date 2021-01-19 14:48
 */
@Component
public class UserIpFilter extends ZuulFilter {
    @Autowired
    private RedisUtils redisUtils;

    @Value("${blackIp.continueCounts}")
    public Integer continueCounts;
    @Value("${blackIp.timeInterval}")
    public Integer timeInterval;
    @Value("${blackIp.limitTimes}")
    public Integer limitTimes;

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {

        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        String userIp = IPUtil.getRequestIp(request);
        // 每个IP在10秒内只能请求一次，若在10秒内多次请求，则禁止访问15秒
        // 判断该ip是否在禁止访问名单中,查询该ip是否还在限制时间内
        // 获取该键的剩余过期时间
        long limitLeftTime = redisUtils.ttl(RedisKeys.getZuulIpLimitTimeKey(userIp));
        if (limitLeftTime > 0) {
            // 还在禁止访问时间内
            stopRequest(context);
            return null;
        }
        // 可以正常访问
        long requestCounts = redisUtils.increment(RedisKeys.getZuulIpKey(userIp), 1);
        if (requestCounts == 1) {
            // 是第一次访问，设置限制是时间
            redisUtils.expire(RedisKeys.getZuulIpKey(userIp), timeInterval);
        }

        if (requestCounts > 1) {
            // 间隔时间内，多次访问
            // 设置禁止访问的时间
            redisUtils.set(RedisKeys.getZuulIpLimitTimeKey(userIp), RedisKeys.getZuulIpLimitTimeKey(userIp), limitTimes);
            stopRequest(context);
        }


        return null;
    }

    private void stopRequest(RequestContext context) {
        // 停止zuul继续乡下路由，禁止请求通信
        context.setSendZuulResponse(false);
        context.setResponseStatusCode(200);
        String str = JsonUtils.objectToJson(Result.errorCustom(ResponseStatusEnum.SYSTEM_ERROR));
        context.setResponseBody(str);
        context.getResponse().setCharacterEncoding("UTF-8");
        context.getResponse().setContentType("application/json");

    }
}
